home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / bash_114.zip / bash-1.14.2 / input.c < prev    next >
C/C++ Source or Header  |  1994-08-10  |  11KB  |  465 lines

  1. /* input.c -- functions to perform buffered input with synchronization. */
  2.  
  3. /* Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5.    This file is part of GNU Bash, the Bourne Again SHell.
  6.  
  7.    Bash is free software; you can redistribute it and/or modify it under
  8.    the terms of the GNU General Public License as published by the Free
  9.    Software Foundation; either version 2, or (at your option) any later
  10.    version.
  11.  
  12.    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  13.    WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14.    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15.    for more details.
  16.  
  17.    You should have received a copy of the GNU General Public License along
  18.    with Bash; see the file COPYING.  If not, write to the Free Software
  19.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. /* similar to stdio, but input-only. */
  22.  
  23. #include "bashtypes.h"
  24. #include <sys/file.h>
  25. #include "filecntl.h"
  26. #include "posixstat.h"
  27. #include <stdio.h>
  28. #include <errno.h>
  29.  
  30. #include "bashansi.h"
  31. #include "config.h"
  32. #include "command.h"
  33. #include "general.h"
  34. #include "input.h"
  35.  
  36. #if !defined (errno)
  37. extern int errno;
  38. #endif /* !errno */
  39.  
  40. #define MAX_INPUT_BUFFER_SIZE    8192
  41.  
  42. #if !defined (SEEK_CUR)
  43. #  define SEEK_CUR 1
  44. #endif /* !SEEK_CUR */
  45.  
  46. void free_buffered_stream ();
  47.  
  48. extern int interactive_shell;
  49.  
  50. int bash_input_fd_changed;
  51. /* This provides a way to map from a file descriptor to the buffer
  52.    associated with that file descriptor, rather than just the other
  53.    way around.  This is needed so that buffers are managed properly
  54.    in constructs like 3<&4.  buffers[x]->b_fd == x -- that is how the
  55.    correspondence is maintained. */
  56. BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
  57. static int nbuffers = 0;
  58.  
  59. #define max(a, b)  (((a) > (b)) ? (a) : (b))
  60.  
  61. #define ALLOCATE_BUFFERS(n) \
  62.     do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
  63.  
  64. /* Make sure `buffers' has at least N elements. */
  65. static void
  66. allocate_buffers (n)
  67.      int n;
  68. {
  69.   register int i, orig_nbuffers;
  70.  
  71.   orig_nbuffers = nbuffers;
  72.   nbuffers = n + 20;
  73.   buffers = (BUFFERED_STREAM **)xrealloc
  74.     (buffers, nbuffers * sizeof (BUFFERED_STREAM *));
  75.  
  76.   /* Zero out the new buffers. */
  77.   for (i = orig_nbuffers; i < nbuffers; i++)
  78.     buffers[i] = (BUFFERED_STREAM *)NULL;
  79. }
  80.  
  81. /* Construct and return a BUFFERED_STREAM corresponding to file descriptor
  82.    FD, using BUFFER. */
  83. static BUFFERED_STREAM *
  84. make_buffered_stream (fd, buffer, bufsize)
  85.      int fd;
  86.      char *buffer;
  87.      int bufsize;
  88. {
  89.   BUFFERED_STREAM *bp;
  90.  
  91.   bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
  92.   ALLOCATE_BUFFERS (fd);
  93.   buffers[fd] = bp;
  94.   bp->b_fd = fd;
  95.   bp->b_buffer = buffer;
  96.   bp->b_size = bufsize;
  97.   bp->b_used = 0;
  98.   bp->b_inputp = 0;
  99.   bp->b_flag = 0;
  100.   if (bufsize == 1)
  101.     bp->b_flag |= B_UNBUFF;
  102.   return (bp);
  103. }
  104.  
  105. /* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
  106. static BUFFERED_STREAM *
  107. copy_buffered_stream (bp)
  108.      BUFFERED_STREAM *bp;
  109. {
  110.   BUFFERED_STREAM *nbp;
  111.  
  112.   if (!bp)
  113.     return ((BUFFERED_STREAM *)NULL);
  114.  
  115.   nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
  116.   xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
  117.   return (nbp);
  118. }
  119.  
  120. /* Check that file descriptor FD is not the one that bash is currently
  121.    using to read input from a script.  FD is about to be duplicated onto,
  122.    which means that the kernel will close it for us.  If FD is the bash
  123.    input file descriptor, we need to seek backwards in the script (if
  124.    possible and necessary -- scripts read from stdin are still unbuffered),
  125.    allocate a new file descriptor to use for bash input, and re-initialize
  126.    the buffered stream. */
  127. int
  128. check_bash_input (fd)
  129.      int fd;
  130. {
  131.   int nfd;
  132.  
  133.   if (fd > 0 && ((bash_input.type == st_bstream && bash_input.location.buffered_fd == fd) ||
  134.            (interactive_shell == 0 && default_buffered_input == fd)))
  135.     {
  136.       /* Sync the stream so we can re-read from the new file descriptor.  We
  137.      might be able to avoid this by copying the buffered stream verbatim
  138.      to the new file descriptor. */
  139.       if (buffers[fd])
  140.     sync_buffered_stream (fd);
  141.  
  142.       /* Now take care of duplicating the file descriptor that bash is
  143.      using for input, so we can reinitialize it later. */
  144.       nfd = fcntl (fd, F_DUPFD, 10);
  145.       if (nfd == -1)
  146.     {
  147.       if (fcntl (fd, F_GETFD, 0) == 0)
  148.         report_error
  149.           ("cannot allocate new file descriptor for bash input from fd %d: %s",
  150.         fd, strerror (errno));
  151.       return -1;
  152.     }
  153.  
  154.       if (buffers[nfd])
  155.     {
  156.       /* What's this?  A stray buffer without an associated open file
  157.          descriptor?  Free up the buffer and report the error. */
  158.       report_error ("check_bash_input: buffer already exists for new fd %d", nfd);
  159.       free_buffered_stream (buffers[nfd]);
  160.     }
  161.  
  162.       /* Reinitialize bash_input.location. */
  163.       if (bash_input.type == st_bstream)
  164.     {
  165.       bash_input.location.buffered_fd = nfd;
  166.       fd_to_buffered_stream (nfd);
  167.       close_buffered_fd (fd);    /* XXX */
  168.     }
  169.       else
  170.     /* If the current input type is not a buffered stream, but the shell
  171.        is not interactive and therefore using a buffered stream to read
  172.        input (e.g. with an `eval exec 3>output' inside a script), note
  173.        that the input fd has been changed.  pop_stream() looks at this
  174.        value and adjusts the input fd to the new value of
  175.        default_buffered_input accordingly. */
  176.     bash_input_fd_changed++;
  177.  
  178.       if (default_buffered_input == fd)
  179.     default_buffered_input = nfd;
  180.     }
  181.   return 0;
  182. }
  183.       
  184. /* This is the buffered stream analogue of dup2(fd1, fd2).  The
  185.    BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
  186.    BUFFERS[fd1] is copied to BUFFERS[fd2].  This is called by the
  187.    redirect code for constructs like 4<&0 and 3</etc/rc.local. */
  188. duplicate_buffered_stream (fd1, fd2)
  189.      int fd1, fd2;
  190. {
  191.   int is_bash_input, m;
  192.  
  193.   if (fd1 == fd2)
  194.     return 0;
  195.  
  196.   m = max (fd1, fd2);
  197.   ALLOCATE_BUFFERS (m);
  198.  
  199.   /* If FD2 is the file descriptor bash is currently using for shell input,
  200.      we need to do some extra work to make sure that the buffered stream
  201.      actually exists (it might not if fd1 was not active, and the copy
  202.      didn't actually do anything). */
  203.   is_bash_input = (bash_input.type == st_bstream) &&
  204.           (bash_input.location.buffered_fd == fd2);
  205.  
  206.   if (buffers[fd2])
  207.     free_buffered_stream (buffers[fd2]);
  208.   buffers[fd2] = copy_buffered_stream (buffers[fd1]);
  209.   if (buffers[fd2])
  210.     buffers[fd2]->b_fd = fd2;
  211.  
  212.   if (is_bash_input)
  213.     {
  214.       if (!buffers[fd2])
  215.     fd_to_buffered_stream (fd2);
  216.     }
  217.   return (fd2);
  218. }
  219.  
  220. /* Return 1 if a seek on FD will succeed. */
  221. #define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
  222.  
  223. /* Take FD, a file descriptor, and create and return a buffered stream
  224.    corresponding to it.  If something is wrong and the file descriptor
  225.    is invalid, return a NULL stream. */
  226. BUFFERED_STREAM *
  227. fd_to_buffered_stream (fd)
  228.      int fd;
  229. {
  230.   char *buffer;
  231.   int size;
  232.   struct stat sb;
  233.  
  234.   if (fstat (fd, &sb) < 0)
  235.     {
  236.       close (fd);
  237.       return ((BUFFERED_STREAM *)NULL);
  238.     }
  239.  
  240.   if (fd_is_seekable (fd) == 0)
  241.     size = 1;
  242.   else
  243.     size = (sb.st_size > MAX_INPUT_BUFFER_SIZE) ? MAX_INPUT_BUFFER_SIZE
  244.                         : sb.st_size;
  245.       
  246.   buffer = (char *)xmalloc (size);
  247.  
  248.   return (make_buffered_stream (fd, buffer, size));
  249. }
  250.  
  251. /* Return a buffered stream corresponding to FILE, a file name. */
  252. BUFFERED_STREAM *
  253. open_buffered_stream (file)
  254.      char *file;
  255. {
  256.   int fd;
  257.  
  258.   fd = open (file, O_RDONLY);
  259.   if (fd == -1)
  260.     return ((BUFFERED_STREAM *)NULL);
  261.   return (fd_to_buffered_stream (fd));
  262. }
  263.  
  264. /* Deallocate a buffered stream and free up its resources.  Make sure we
  265.    zero out the slot in BUFFERS that points to BP. */
  266. void
  267. free_buffered_stream (bp)
  268.      BUFFERED_STREAM *bp;
  269. {
  270.   int n;
  271.  
  272.   if (!bp)
  273.     return;
  274.  
  275.   n = bp->b_fd;
  276.   if (bp->b_buffer)
  277.     free (bp->b_buffer);
  278.   free (bp);
  279.   buffers[n] = (BUFFERED_STREAM *)NULL;
  280. }
  281.  
  282. /* Close the file descriptor associated with BP, a buffered stream, and free
  283.    up the stream.  Return the status of closing BP's file descriptor. */
  284. int
  285. close_buffered_stream (bp)
  286.      BUFFERED_STREAM *bp;
  287. {
  288.   int fd;
  289.  
  290.   if (!bp)
  291.     return (0);
  292.   fd = bp->b_fd;
  293.   free_buffered_stream (bp);
  294.   return (close (fd));
  295. }
  296.  
  297. /* Deallocate the buffered stream associated with file descriptor FD, and
  298.    close FD.  Return the status of the close on FD. */
  299. int
  300. close_buffered_fd (fd)
  301.      int fd;
  302. {
  303.   if (fd >= nbuffers || !buffers || !buffers[fd])
  304.     return (close (fd));
  305.   return (close_buffered_stream (buffers[fd]));
  306. }
  307.  
  308. /* Read a buffer full of characters from BP, a buffered stream. */
  309. static int
  310. b_fill_buffer (bp)
  311.      BUFFERED_STREAM *bp;
  312. {
  313.   do
  314.     {
  315.       bp->b_used = read (bp->b_fd, bp->b_buffer, bp->b_size);
  316.     }
  317.   while (bp->b_used < 0 && errno == EINTR);
  318.   if (bp->b_used <= 0)
  319.     {
  320.       bp->b_buffer[0] = 0;
  321.       if (bp->b_used == 0)
  322.     bp->b_flag |= B_EOF;
  323.       else
  324.     bp->b_flag |= B_ERROR;
  325.       return (EOF);
  326.     }
  327.   bp->b_inputp = 0;
  328.   return (bp->b_buffer[bp->b_inputp++] & 0xFF);
  329. }
  330.  
  331. /* Get a character from buffered stream BP. */
  332. #define bufstream_getc(bp) \
  333.   (bp->b_inputp == bp->b_used || !bp->b_used) \
  334.           ? b_fill_buffer (bp) \
  335.         : bp->b_buffer[bp->b_inputp++] & 0xFF
  336.  
  337. /* Push C back onto buffered stream BP. */
  338. static int
  339. bufstream_ungetc(c, bp)
  340.      int c;
  341.      BUFFERED_STREAM *bp;
  342. {
  343.   if (c == EOF || bp->b_inputp == 0)
  344.     return (EOF);
  345.  
  346.   bp->b_buffer[--bp->b_inputp] = c;
  347.   return (c);
  348. }
  349.  
  350. /* Seek backwards on file BFD to synchronize what we've read so far
  351.    with the underlying file pointer. */
  352. int
  353. sync_buffered_stream (bfd)
  354.      int bfd;
  355. {
  356.   BUFFERED_STREAM *bp;
  357.   int chars_left;
  358.  
  359.   bp = buffers[bfd];
  360.   if (!bp)
  361.     return (-1);
  362.   chars_left = bp->b_used - bp->b_inputp;
  363.   if (chars_left)
  364.     lseek (bp->b_fd, -chars_left, SEEK_CUR);
  365.   bp->b_used = bp->b_inputp = 0;
  366.   return (0);
  367. }
  368.  
  369. int
  370. buffered_getchar ()
  371. {
  372.   return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
  373. }
  374.  
  375. int
  376. buffered_ungetchar (c)
  377.      int c;
  378. {
  379.   return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
  380. }
  381.  
  382. /* Make input come from file descriptor BFD through a buffered stream. */
  383. void
  384. with_input_from_buffered_stream (bfd, name)
  385.      int bfd;
  386.      char *name;
  387. {
  388.   INPUT_STREAM location;
  389.  
  390.   location.buffered_fd = bfd;
  391.   /* Make sure the buffered stream exists. */
  392.   fd_to_buffered_stream (bfd);
  393.   init_yy_io (buffered_getchar, buffered_ungetchar, st_bstream, name, location);
  394. }
  395.  
  396. #if defined (TEST)
  397.  
  398. char *
  399. xmalloc(s)
  400. int s;
  401. {
  402.     return ((char *)malloc (s));
  403. }
  404.  
  405. char *
  406. xrealloc(s, size)
  407. char    *s;
  408. int    size;
  409. {
  410.     if (!s)
  411.         return((char *)malloc (size));
  412.     else
  413.         return((char *)realloc (s, size));
  414. }
  415.  
  416. void
  417. init_yy_io ()
  418. {
  419. }
  420.  
  421. process(bp)
  422. BUFFERED_STREAM *bp;
  423. {
  424.     int c;
  425.  
  426.     while ((c = bufstream_getc(bp)) != EOF)
  427.         putchar(c);
  428. }
  429.  
  430. BASH_INPUT bash_input;
  431.  
  432. struct stat dsb;        /* can be used from gdb */
  433.  
  434. /* imitate /bin/cat */
  435. main(argc, argv)
  436. int    argc;
  437. char    **argv;
  438. {
  439.     register int i;
  440.     BUFFERED_STREAM *bp;
  441.  
  442.     if (argc == 1) {
  443.         bp = fd_to_buffered_stream (0);
  444.         process(bp);
  445.         exit(0);
  446.     }
  447.     for (i = 1; i < argc; i++) {
  448.         if (argv[i][0] == '-' && argv[i][1] == '\0') {
  449.             bp = fd_to_buffered_stream (0);
  450.             if (!bp)
  451.                 continue;
  452.             process(bp);
  453.             free_buffered_stream (bp);
  454.         } else {
  455.             bp = open_buffered_stream (argv[i]);
  456.             if (!bp)
  457.                 continue;
  458.             process(bp);
  459.             close_buffered_stream (bp);
  460.         }
  461.     }
  462.     exit(0);
  463. }
  464. #endif
  465.